/**
 * 
 */
package com.server;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.tool.Log;
import com.tool.Parameter;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.io.watch.SimpleWatcher;
import cn.hutool.core.io.watch.WatchMonitor;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

/**
 * @author w.weizhen
 *
 */
public class StartServer 
{
//    public static void main(String[] args)
//    {
//        System.out.println(ls("D:\\hynetic"));
//    }
    
    //启动服务
    public static void run()
    {
        //扫描文件,生成索引
        scan();
        
        //监听文件变化
        monitor();
        
        //创建服务
        createServer();
    }
    
    //创建服务
    private static void createServer()
    {
        HttpUtil.createServer(Parameter.port)
        .setRoot(Parameter.tmp_path)
        .start();
    }
    
    private static void monitor()
    {
        Log.log("创建文件监听");
        WatchMonitor.createAll(FileUtil.file(Parameter.local_file), new SimpleWatcher(){
            @Override
            public void onCreate(WatchEvent<?> event, Path currentPath) {
                Log.log("文件被创建: " + event.context());
                scan();
            }
            @Override
            public void onModify(WatchEvent<?> event, Path currentPath) {
                Log.log("文件被修改: " + event.context());
                scan();
            }
            @Override
            public void onDelete(WatchEvent<?> event, Path currentPath) {
                Log.log("文件被删除: " + event.context());
                scan();
            }
            @Override
            public void onOverflow(WatchEvent<?> event, Path currentPath) {
                Log.log("文件被覆盖: " + event.context());
                scan();
            }
        })
        //设置监听目录的最大深入，目录层级大于制定层级的变更将不被监听，默认只监听当前层级目录
        .setMaxDepth(5)
        //启动监听
        .start();
    }
    
    //扫描文件
    private static void scan()
    {
        Log.log("开始扫描文件!");
        //没有文件，不需要重新生成索引文件
        if(FileUtil.isDirEmpty(FileUtil.file(Parameter.local_file))) {Log.log("空目录,结束扫描文件!");return;}
        List<String> paths = ls(Parameter.local_file);
        if(paths == null || paths.size() < 1)
        {
            Log.log("空目录,结束扫描文件!");
            return;
        }
        //生成索引的空白json对象
        JSONObject datas = JSONUtil.createObj();
        List<String> md5s = new ArrayList<String>();
        for (int i = 0; i < paths.size(); i++)
        {
            String path = paths.get(i);
            File file = FileUtil.file(path);
            //生成文件索引
            JSONObject data = JSONUtil.createObj();
            String name = file.getAbsolutePath().substring(Parameter.local_file.length(), file.getAbsolutePath().length());
            String md5 = SecureUtil.md5(file);
            md5s.add(md5);
            data.set("name", name)//文件名称
            .set("size", FileUtil.size(file))//文件大小
            .set("md5", md5);//文件md5
            datas.set(data.getStr("name"), data);
            //将文件复制到临时目录，如果临时目录中不存在该文件或者文件md5不同，则复制文件
            File tmp_file = FileUtil.file(Parameter.tmp_path + name);
            if(!FileUtil.exist(tmp_file) || !Objects.equals(md5, SecureUtil.md5(tmp_file)))
            {
                FileUtil.copy(file, tmp_file, true);
            }
            Log.log("data: " + data.toString());
        }
        Log.log("datas: "+datas.toString());
        //重新生成索引文件
        FileWriter writer = new FileWriter(Parameter.indexes_path);
        writer.write(datas.toString());
        //处理被删除的文件，如果文件名称在索引中不存在[在原目录中被删除了]，则删除临时目录中的文件
        paths = ls(Parameter.tmp_path);
        if(paths == null || paths.size() < 1)
        {
            Log.log("空目录,结束扫描文件!");
            return;
        }
        for (int i = 0; i < paths.size(); i++)
        {
            String path = paths.get(i);
            File file = FileUtil.file(path);
            if(!md5s.contains(SecureUtil.md5(file)) && !Objects.equals(Parameter.indexes, file.getName()))
            {
                file.delete();
            }
        }
        Log.log("结束扫描文件!");
    }
    
    /**
     * 递归得到目录下所有文件
     * 
     * @return
     */
    private static List<String> ls(String path)
    {
        List<String> paths = new ArrayList<String>();
        File[] files = FileUtil.ls(path);
        
        for (File file : files)
        {
            if (file.isDirectory())
            {
                List<String> cpaths = ls(file.getAbsolutePath());
                if(cpaths != null && cpaths.size() > 0)
                {
                    paths.addAll(cpaths);
                }
            }
            else
            {
                paths.add(file.getAbsolutePath());
            }
        }
        return paths;
    }
    
}